import threading
import time
import socket
from xml_parser import *
import xml.sax
import pygame
import cPickle

class game_info_server(threading.Thread):
    def __init__(self, game):
        self.game = game
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(("", 1976))
        self.sock.settimeout(5.0)
        self.stop_request = False
        threading.Thread.__init__(self)
        
    def setTimeout(self, timeout):
        self.sock.settimeout(timeout)
    
    def run(self):
        while not self.stop_request:
            try:
                data, addr = self.sock.recvfrom(4000)
                handler = game_info_handler_server()
                xml.sax.parseString(data, handler)
                if handler.request_type == "info_request":
                    message = "<tank_game_info "
                    message+= "name=\"%s\" " % self.game.config.game_name
                    message+= "port=\"%i\" " % self.game.config.game_port
                    message+= "players=\"%i\" " % len(self.game.players)
                    message+= "open_spots=\"%i\" " % (self.game.config.game_max_players - len(self.game.players))
                    message+= ">"
                    message+= "</tank_game_info>"
                    self.sock.sendto(message, addr)
                elif handler.request_type == "join_request":
                    if len(self.game.players) < self.game.config.game_max_players:
                        answer = "yes"
                        misc = {}
                        misc['type'] = 'player_join_game'
                        misc['callsign'] = handler.callsign
                        misc['addr'] = addr
                        pygame.event.post(pygame.event.Event(pygame.USEREVENT, {'details':misc}))
                    else:
                        answer = "no"
                    message = "<tank_game_join_response answer=\"%s\" port=\"%i\" />" % (answer, self.game.config.game_port)
                    self.sock.sendto(message, addr)
                if(self.stop_request):
                    break
            except:
                if self.stop_request:
                    break
            
    def stop(self):
        self.stop_request = True
    

class game_setup_server:
    def __init__(self, game):
        self.game = game
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(("", 1977))
        self.sock.settimeout(5.0)
    
    def start_game(self):
        message = "<tank_game_start>"
        for i in range(len(self.game.players)):
            player = self.game.players[i]
            player.player_id = i
            message+= "<player callsign=\"%s\" start_pos=\"%i,%i\" player_id=\"%i\" />" % (player.callsign, player.start_info['start_position'][0], player.start_info['start_position'][1], i)
        message+= "</tank_game_start>"
        message_length = len(message)
        
        for player in self.game.players:
            resend = True
            while resend:
                sent = self.sock.sendto(message, self.game.players[player].addr)
                if not sent < message_length:
                    resend = False
        
        #awaiting acknowledgements of ready to go
        handler = game_setup_handler_server()
        readies = 0
        stop = False
        while not stop:
            try:
                data, addr = self.sock.recvfrom(4000)
                xml.sax.parseString(data, handler)
                if handler.request_type == "tank_game_ready":
                    self.game.players[handler.player_id].ready = True
                    readies+= 1
                    if readies == len(self.game.players) -1:
                        stop = True
                        break
            except:
                "Error in try, except block starting at line 74 in game_server.py"
        if readies < (len(self.game.players)-1):
            return False
        
        return True
    
    def close(self):
        self.sock.close()
        
class game_loop_server(threading.Thread):
    def __init__(self, game):
        self.game = game
        self.game_logic = self.game.game_logic
        
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(("", self.game.config.game_port))
        self.sock.settimeout(0.5)
        threading.Thread.__init__(self)
    
    def run(self):
        stop = False
        while not stop:
            try:
                data, addr = self.sock.recvfrom(4000)
                detail_list = cPickle.loads(data)
                for detail in detail_list:
                    detail['from_host'] = True
                    pygame.event.post(pygame.event.Event(pygame.USEREVENT, {'details': detail}))
            except:
                pass
                
            if self.game_logic.loop_quit == True:
                stop = True
        self.sock.close()
            
